using System;
using System.Xml.XPath;
using AntEater.ComponentModel.BuildElements;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Collections.ObjectModel;
using AntEater.ComponentModel;

namespace AntEater.Runtime.Services.Transformation
{
    /// <summary>
    /// This Service Transforms the AntEater Build Element
    /// Component Model into an MSBuild Xml File.
    /// </summary>
    public class BuildElementToXmlTransformationService : RuntimeServiceBase, IBuildElementToXmlTransformationService
    {

        /// <summary>
        /// Gets a value indicating whether this instance is reusable.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is reusable; otherwise, <c>false</c>.
        /// </value>
        public override bool IsReusable {
            get {
                return false;
            }
        }

        private List<TransformationError> _errors;

        private TransformerContext _transformerContext;

        /// <summary>
        /// Transforms the specified source.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="buildFilePath">The build file path.</param>
        /// <returns></returns>
        public BuildElementToXmlTransformationResult Transform(BuildFileDefinition source,string buildFilePath) {
            BuildElementToXmlTransformationResult result = null;

            _transformerContext = new TransformerContext(this, buildFilePath);

            XmlWriterSettings settings = new XmlWriterSettings();
            MemoryStream buildFile = new MemoryStream();

            settings.Indent = true;

            using (XmlWriter buildFileWriter = XmlWriter.Create(buildFile, settings)) {

                _errors = new List<TransformationError>();

                foreach (IBuildElement element in source.RootBuildElement.ChildElements) {
                    WriteNodeLevel(element, buildFileWriter, _errors, _transformerContext);
                }

            }

            //MoveTo Stream Begin
            buildFile.Seek(0, SeekOrigin.Begin);

            result = new BuildElementToXmlTransformationResult(buildFile, _errors);
   
            return result;

        }

        /// <summary>
        /// Writes the node level.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="writer">The writer.</param>
        /// <param name="errors">The errors.</param>
        /// <param name="transformerContext">The transformer context.</param>
        private void WriteNodeLevel(IBuildElement element, XmlWriter writer, List<TransformationError> errors, TransformerContext transformerContext) {
            
            IBuildElementTransformer transformer
                = BuildElementTransformerFactory.GetTransformer(element.GetType(), transformerContext);

            if (transformer != null) {

                transformer.GetChildElementsXml += new GetChildElementsXml(GetChildElementsXml);

                transformer.GetXml(element, writer, errors);

            }

        }

        /// <summary>
        /// Gets the child elements XML.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="writer">The writer.</param>
        private void GetChildElementsXml(IBuildElement element, XmlWriter writer) {

            IContainerBuildElement container 
                = element as IContainerBuildElement;

            if (container != null) {
                foreach (IBuildElement childElement in container.ChildElements) {
                    WriteNodeLevel(childElement, writer, _errors, _transformerContext);
                }
            }

        }
    }
}
